// leetcode.algorithms.cpp : This file contains the 'main' function. Program execution begins and ends there.
//

#define _CRT_SECURE_NO_WARNINGS

#include <thread>
#include <future>
#include <utility>
#include <stack>
#include <queue>
#include <iostream>
#include <vector>
#include <algorithm>
#include <map>
#include <unordered_map>
#include <python3.9/Python.h>
#include <glog/logging.h>

#include "../leetcode.algorithms/leetcode.algorithms-arr.hpp"
#include "../leetcode.algorithms/leetcode.algorithms-sort.hpp"
#include "../leetcode.algorithms/leetcode.algorithms-string.hpp"

using namespace std;

void SplitPathByLastOccurenceOf(const std::string& path, const std::string& delimiter, const bool left_first, std::string* left, std::string* right) {
  CHECK_NOTNULL(left);
  CHECK_NOTNULL(right);
  int position_delimiter = 0;
  if (left_first)
    position_delimiter = path.find_first_of(delimiter);
  else
    position_delimiter = path.find_last_of(delimiter);
  if (position_delimiter != std::string::npos) {
    *left = path.substr(0, position_delimiter);
    *right = path.substr(position_delimiter + 1);
  }
  else {
    if (!left_first) {
      left->clear();
      *right = path.substr(position_delimiter + 1);
    }
    else {
      right->clear();
      *left = path.substr(position_delimiter + 1);
    }
  }
}

void SplitPathAndFilename(const std::string& path_with_file, std::string* path, std::string* filename) {
  CHECK_NOTNULL(path);
  CHECK_NOTNULL(filename);
  constexpr auto left_first_ = false;
  SplitPathByLastOccurenceOf(path_with_file, "\\\\", left_first_, path, filename);
}

void exec(std::string filePath, std::promise<bool>& out)
{
  Py_SetPythonHome(L"C:/Users/meiti/AppData/Local/Programs/Python/Python38");
  PyObject* module, * func, * prm, * ret;
  Py_Initialize();
  if (!Py_IsInitialized())
    out.set_value(false);

  std::string path, name;
  SplitPathAndFilename(filePath, &path, &name);
  if (path.back() != '//')  path += "//";
  std::wstring widestr = std::wstring(path.begin(), path.end());
  name = name.substr(0, name.length() - 3);
  PySys_SetPath(widestr.c_str());
  module = PyImport_ImportModule(name.c_str());

  if (module != 0)//Asks if the script was loaded at all.
  {
    func = PyObject_GetAttrString(module, "compare_function");//Opens a function within the python script. Notice that you must use a function within the python script, because otherwise you can't return anything.
    prm = Py_BuildValue("(ss)", "Hello", "Mars");//The "(ss)" means two strings are passed (replace with "i" for integer for instance), the "Hello" and "Mars" are the strings i pass to the script.
    ret = PyObject_CallObject(func, prm);//Returns some python object i have literally no idea about ...

    const char* result = PyUnicode_AsUTF8(ret);// ... but luckily there's a function to cast it back to a c-compatible char*!
    printf("The Script decdided that '%s' is longer!", result);

    Py_DECREF(module);//cleanup?
    Py_DECREF(func);//cleanup?
    Py_DECREF(prm);//cleanup?
    Py_DECREF(ret);//cleanup?
  }
  else//No script found
  {
    printf("Error: No script file named \"script.py\" was found!\n");
  }

  Py_Finalize();
  out.set_value(true);
}

int main(int argc, char** argv)
{
  //std::promise<bool> promiseObj;
  //std::future<bool> futureObj = promiseObj.get_future();
  //std::thread t1(exec, "d:\\test.py", std::ref(promiseObj));

  //t1.join();
  //if (futureObj.get())
  //  std::cout << "\nout is true";

  str_solution str;
  str.isPalindrome("A man, a plan, a canal: Panama");

  MedianFinder mf;
  mf.addNum(6);
  mf.addNum(10);
  mf.addNum(2);
  mf.addNum(6);
  mf.addNum(0);
  mf.addNum(1);
  mf.addNum(0);
  std::cout << mf.findMedian();
  vector<int> nums = { 2,7,11,15,0,0 };
  vector<int> nums2 = { 7,11 };
  sort_solution sort;
  sort.merge(nums, 4, nums2, 2);
  sort.countPrimes(10);

  array_solution s;
  vector<vector<int>> m1 = { {1, 5, 9}, { 10, 11, 13 }, { 12, 13, 15 } };
  vector<vector<char>> sudoku = { {'5', '3', '.', '.', '7', '.', '.', '.', '.'},
                                  {'6', '.', '.', '1', '9', '5', '.', '.', '.'},
                                  {'.', '9', '8', '.', '.', '.', '.', '6', '.'},
                                  {'8', '.', '.', '.', '6', '.', '.', '.', '3'},
                                  {'4', '.', '.', '8', '.', '3', '.', '.', '1'},
                                  {'7', '.', '.', '.', '2', '.', '.', '.', '6'},
                                  {'.', '6', '.', '.', '.', '.', '2', '8', '.'},
                                  {'.', '.', '.', '4', '1', '9', '.', '.', '5'},
                                  {'.', '.', '.', '.', '8', '.', '.', '7', '9'}, };
  s.validSudoku(sudoku);
  s.kthSmallest(m1, 8);
  nums = { 2,7,11,15,7 };
  nums2 = { 7,11 };
  vector<vector<int>> matrix = { {5, 1, 9, 11}, {2, 4, 8, 10}, {13, 3, 6, 7}, {15, 14, 12, 16} };
  s.rotate(matrix);

  s.intersect(nums, nums2);

  s.TwoSum(nums, 9);

  nums = { 1,1,2 };
  s.removeDuplicateNoMoreThanOne(nums);

  nums = { 0,0,1 };
  s.moveZeroes(nums);

  nums = { 1,2,3,4 };
  s.rotate(nums, 2);
  s.rotateFast(nums, 2);

  nums = { 1,1,2 };
  s.containsDuplicate(nums);

  std::cout << "Hello World!\n";
}